﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ttlang.type.code
{
    public struct srcinfo
    {
        public int fileid;
        public int startline;
        public int startcol;
        public int endline;
        public int endcol;
    }

    //语法节点，不需要和AST一一对应，AST可能会啰嗦，过程中整理一下
    public enum CodeType
    {
        UNDEFINED = 0,
        CODEBLOCK,

        CONST = 0x1000,//常量系列
        CONST_BIN,//二进制值
        CONST_HEX,//十六进制值
        CONST_INT,//十进制值，可能有负号
        CONST_FLOAT,//含有小数的值，可能有符号
        CONST_STRING,//字符串
        CONST_BOOL,

        EXPRS = 0x2000,//注意自增表达式 在 ttlang中无返回值，不是expr
                       //不允许 return ++i 也不允许 return i++
        EXPR_UNARY,
        EXPR_CALL,
        EXPR_NEW,
        EXPR_GROUP,
        EXPR_ARRAY,
        EXPR_MATH,//特指左右两值的表达式
        EXPR_3OP,//三元表达式
        EXPR_TEMPVAR,//临时变量引用
        EXPR_ARGVAR,//參數引用
        EXPR_NUMBER,
        EXPR_CAST,
        EXPR_STRING,
        EXPR_METHOD,
        EXPR_MEMBER,//成员访问 a.b
        EXPR_CONTAINER,//container 是指一个type或者namespace

        CODES = 0x3000,
        CODE_COMMENT,
        CODE_VALUEDEF,
        CODE_SET,
        CODE_SELFOP,
        CODE_IF,
        CODE_FOR,
        CODE_CALL,
        CODE_RETURN,

    }
    public enum CodeElementType
    {
        ErrorType,


        Code,
        CodeArray,
       
        TTType,
        TTContainer,
        TTMethod,
        TTVar,
        TTArg,

        Const_String,
        Other_String
    }

    public class CodeElement
    {
        public static CodeElement TTCode(TTCode value)
        {
            CodeElement elem = new CodeElement();
            elem.ttcode = value;
            elem.type = CodeElementType.Code;
            return elem;
        }
        public static CodeElement TTCodeArray(IList<TTCode> value)
        {
            CodeElement elem = new CodeElement();
            elem.ttcodeArray = new TTCode[value.Count];
            for (var i = 0; i < value.Count; i++)
            {
                elem.ttcodeArray[i] = value[i];
            }
            elem.type = CodeElementType.CodeArray;
            return elem;
        }
        public static CodeElement TTType(TTType value)
        {
            CodeElement elem = new CodeElement();
            elem.tttype = value;
            elem.type = CodeElementType.TTType;
            return elem;
        }
        public static CodeElement TTMethod(TTMethod value)
        {
            CodeElement elem = new CodeElement();
            elem.ttmethod = value;
            elem.type = CodeElementType.TTMethod;
            return elem;
        }
        public static CodeElement TTVar(TTVar value)
        {
            CodeElement elem = new CodeElement();
            elem.ttvar = value;
            elem.type = CodeElementType.TTVar;
            return elem;
        }
        public static CodeElement TTArg(TTArg value)
        {
            CodeElement elem = new CodeElement();
            elem.ttarg = value;
            elem.type = CodeElementType.TTArg;
            return elem;
        }
        public static CodeElement TTMember(IMember value)
        {
            if (value is TTMethod m)
                return TTMethod(m);
            else if (value is TTVar v)
                return TTVar(v);
            throw new Exception("not support member.");
        }
        public static CodeElement Const_String(string value)
        {
            CodeElement elem = new CodeElement();
            elem.strvalue = value;
            elem.type = CodeElementType.Const_String;
            return elem;
        }
        public static CodeElement Other_String(string value)
        {
            CodeElement elem = new CodeElement();
            elem.strvalue = value;
            elem.type = CodeElementType.Const_String;
            return elem;
        }
        public CodeElementType type;
        public string helpinfo;

        public TTCode ttcode;
        public TTCode[] ttcodeArray;
        public TTType tttype;
        public TTMethod ttmethod;
        public TTVar ttvar;
        public TTArg ttarg;
        public string strvalue;

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
            {
                space += "    ";
            }
            switch (type)
            {
                case CodeElementType.Code:
                    ttcode.Dump(deep);
                    break;
                case CodeElementType.CodeArray:
                    {
                        Console.WriteLine(space + "[");
                        for (var i = 0; i < ttcodeArray.Length; i++)
                        {
                            ttcodeArray[i].Dump(deep + 1);
                        }
                        Console.WriteLine(space + "]");
                    }
                    break;
                case CodeElementType.TTType:
                    Console.WriteLine(space + "type:" + tttype.name);
                    break;
                case CodeElementType.TTMethod:
                    Console.WriteLine(space + "method:" + ttmethod.name);
                    break;
                case CodeElementType.TTVar:
                    Console.WriteLine(space + "var:" + ttvar.name);
                    break;
                case CodeElementType.TTArg:
                    Console.WriteLine(space + "arg:" + ttarg.name);
                    break;
                case CodeElementType.Const_String:
                    Console.WriteLine(space + "Const_String:" + strvalue);
                    break;
                case CodeElementType.Other_String:
                    Console.WriteLine(space + "Other_String:" + strvalue);
                    break;
                default:
                    throw new Exception("error type.");
            }
        }
    }
    public class TTCode
    {
        public CodeType type;
        public srcinfo srcinfo;
        public bool isExpr;
        public bool isConst;
        public CodeElement[] elements;


        /// <summary>
        /// inedit不为空表示这个code是未编译完成的
        /// </summary>
        public CodeInEdit inedit;
        public TTType GetExprType()
        {
            if (!isExpr) 
                throw new Exception("not expr.");
            if (elements[0].tttype == null) throw new Exception("error type.");
            return elements[0].tttype;
        }
        public void Dump(int deep)
        {
            string space = "";
            for(var i=0;i<deep;i++)
            {
                space += "    ";
            }
            Console.WriteLine(space+type + "(isexpr=" + isExpr + ",isConst=" + isConst + ")");
            Console.WriteLine(space + "{");
            for(var i=0;i<elements.Length;i++)
            {
                elements[i].Dump(deep + 1);
            }
            Console.WriteLine(space + "}");
        }
    }
    public class CodeInEdit
    {

    }
}
